#Context
BART, short for “Bay Area Rapid Transit”, is the transit system severing the San Francisco Bay Area in California. BART operates six routes, 46 stations, and and 112 miles of track. It serves an average weekday ridership of 423,000 people, making it the fifth-busiest rapid transit system in the United States.
This dataset contains daily information on BART ridership for a period covering all of 2016 and part of 2017. Unlike some other rapid transit system datasets, this data includes movements between specific stations (there are just over 2000 station-to-station combinations).
#Content
This dataset is split in three files. station_info.csv includes generic information on individual stations. date-hour-soo-dest-2017.csv contains daily inter-station ridership for (part of) 2017. date-hour-soo-dest-2016.csv contains daily inter-station ridership for all of 2016.
#Questions that are to be answered
Which BART station is the busiest? Top 5 popular routes? What is the least popular BART route? When is the best time to go to SF if you want to find a seat? Which day of the week is the busiest? How many people take the BART late at night? Does the BART ever stop in a station without anyone going off or on?
Note :- Number of passengers (Throughput) that went between two stations (Origin and Destination) in a given time (DateTime) in 2017.
libraries used for the EDA.
library(data.table)
data.table 1.12.2 using 2 threads (see ?getDTthreads). Latest news: r-datatable.com
library(ggplot2)
library(plotly)
Attaching package: ‘plotly’
The following object is masked from ‘package:ggplot2’:
last_plot
The following object is masked from ‘package:stats’:
filter
The following object is masked from ‘package:graphics’:
layout
library(zoo)
Attaching package: ‘zoo’
The following objects are masked from ‘package:base’:
as.Date, as.Date.numeric
library(lubridate)
Attaching package: ‘lubridate’
The following objects are masked from ‘package:data.table’:
hour, isoweek, mday, minute, month, quarter, second, wday, week, yday, year
The following object is masked from ‘package:base’:
date
library(dplyr)
Attaching package: ‘dplyr’
The following objects are masked from ‘package:lubridate’:
intersect, setdiff, union
The following objects are masked from ‘package:data.table’:
between, first, last
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
library(quantmod)
Loading required package: xts
Attaching package: ‘xts’
The following objects are masked from ‘package:dplyr’:
first, last
The following objects are masked from ‘package:data.table’:
first, last
Loading required package: TTR
Version 0.4-0 included new data defaults. See ?getSymbols.
library(reshape2)
Attaching package: ‘reshape2’
The following objects are masked from ‘package:data.table’:
dcast, melt
library(plyr)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
You have loaded plyr after dplyr - this is likely to cause problems.
If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
library(plyr); library(dplyr)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Attaching package: ‘plyr’
The following objects are masked from ‘package:dplyr’:
arrange, count, desc, failwith, id, mutate, rename, summarise, summarize
The following object is masked from ‘package:lubridate’:
here
The following objects are masked from ‘package:plotly’:
arrange, mutate, rename, summarise
library(scales)
library(RColorBrewer)
#library(devtools)
Reading all the data into R.
data1 <- fread("date-hour-soo-dest-2016.csv",stringsAsFactors = TRUE)
|--------------------------------------------------|
|==================================================|
data2 <- fread("date-hour-soo-dest-2017.csv",stringsAsFactors = TRUE)
data3 <- fread("station_info.csv",stringsAsFactors = TRUE)
As the data1 and data2 represent the same structure of the data,so now we are merging those 2 data
data<-rbind(data1,data2)
Removing the above 2 data frames in R
rm(data1)
rm(data2)
converting the date time column correct format in R.
data$DateTime <- as.POSIXct(data$DateTime, format="%Y-%m-%d %H:%M:%S")
Now we are extracting months,year,weekdays,hours
data$year=year(data$DateTime)
data$month=month(data$DateTime)
data$weekDays=weekdays(data$DateTime)
data$hours = hour(data$DateTime)
Now we are extracting seasons.
Spring :- March,April,May Summer :- June,July,August Autum :- September,October,November Winter :- December,January,February
indx <- setNames( rep(c('winter', 'spring', 'summer',
'fall'),each=3), c(12,1:11))
#data1=data
data$season<-unname(indx[as.character(data$month)])
Extracting hours from date time column. This is 24 hours clock
12 am - 6 am :- Night. 6 am - 12 noon :- Morning. 12 noon - 6pm :- AfterNoon.2 6pm - 11pm ;- Evening.
# create breaks
breaks <- hour(hms("00:00", "6:00", "12:00", "18:00", "23:59"))
Some strings failed to parse, or all strings are NAs
# labels for the breaks
labels <- c("Night", "Morning", "Afternoon", "Evening")
data$dayCycle <- cut(x=hour(data$DateTime), breaks = breaks, labels = labels, include.lowest=TRUE)
#unique(hour(data$DateTime))
unique(data$dayCycle)
[1] Night Morning Afternoon Evening
Levels: Night Morning Afternoon Evening
checking how many unique source stations
cat("The number of origin stations is :- ", length(unique(data$Origin)))
The number of origin stations is :- 46
cat("\n The number of Destination stations is :- ", length(unique(data$Destination)))
The number of Destination stations is :- 46
so there are 46 the number of origin and destindation places are 46.
checking those entries who ’s source and destination is same.
length(data[data$Origin==data$Destination,][Origin=="12TH",.N,c('Origin','Destination','hours','Throughput')])
[1] 5
unique(data[data$Origin==data$Destination,][,c("Origin","Destination")])
The source and destination are same ,that ’s because the people were staying in the same station for that particular hour.so this data tells about these people.
#Which BART station is the busiest?
data1=data[,list(Throughput=sum(Throughput)), by='Destination'][order(Throughput,Destination,decreasing=TRUE)]
Plotting the top 5 busiest stations.
ggplotly( ggplot(data1[1:5,],aes(x=as.factor(Destination),y=Throughput))+
geom_segment( aes(x=as.factor(Destination), xend=as.factor(Destination), y=0, yend=Throughput)) +ylim(0,22000000)+
geom_point( size=5, color="steelblue", fill=alpha("steelblue", 0.3), alpha=0.7, shape=21, stroke=2)+theme(panel.background = element_rect(fill = ' white'))+geom_text(aes(label=Throughput), vjust=-2, color="black", size=3.4)+coord_flip()+labs(title = "The Top 5 busiest BART Stations",x="Station code",y="Population")+theme(plot.title = element_text(hjust = 0.5,face = "bold",color = "Black")))
As we see Embarcadero (EMBR) is the BART station was the most busest station in 2016 and 2017 ,followed by Montgomery St. (MONT), Powell St. (POWL),Civic Center/UN Plaza (CIVC) and Downtown Berkeley (DBRK)
Least popular BART station.
ggplotly(ggplot(data1[41:45,],aes(x=as.factor(Destination),y=Throughput))+
geom_segment( aes(x=as.factor(Destination), xend=as.factor(Destination), y=0, yend=Throughput)) +ylim(0,2200000)+
geom_point( size=5, color="steelblue", fill=alpha("steelblue", 0.3), alpha=0.7, shape=21, stroke=2)+theme(panel.background = element_rect(fill = ' white'))+geom_text(aes(label=Throughput), vjust=-1, color="black", size=3.4)+coord_flip()+labs(title = "The Least 5 busiest BART Stations",x="Station code",y="Population")+theme(plot.title = element_text(hjust = 0.5,face = "bold",color = "Black")))
The least busiest stations are Oakland Airport (OAKL).
Showing these stats of population in terms of percentage.
data1 %>%
group_by(Destination) %>%
plot_ly(labels = ~as.factor(Destination), values = ~Throughput) %>%
add_pie(hole = 0.6) %>%
layout(title = "The Population in BART Stations", showlegend = F,
xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))
removing the subset data.
rm(data1)
#What is the least popular BART route?
data$roots<- with(data, paste0(Origin,"-",Destination))
data
data[!(Origin==Destination),list(Throughput=sum(Throughput)),by=c("roots")][order(Throughput,roots,decreasing=TRUE)]
ggplotly( ggplot(data[!(Origin==Destination),list(Throughput=sum(Throughput)),by=c("roots")][order(Throughput,roots,decreasing=TRUE)][1:5,],aes(x=as.factor(roots),y=Throughput))+geom_bar(fill="steelblue",bin = 50,width = 0.2 ,stat="identity",na.rm = TRUE)+geom_text(aes(label=Throughput), vjust=-1, color="black", size=3.4)+labs(title = "The top 5 busy roots of BART",x="Roots",y="Populations")+theme(plot.title = element_text(hjust = 0.5,face = "bold",color = "black"))+theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
panel.background = element_blank(), axis.line = element_line(colour = "black"))+coord_flip())
Ignoring unknown parameters: bin
ggplotly(ggplot(data[!(Origin==Destination),list(Throughput=sum(Throughput)),by=c("roots")][order(Throughput,roots,decreasing=TRUE)][2065:2070,],aes(x=as.factor(roots),y=Throughput))+geom_bar(fill="steelblue",bin = 50,width = 0.2 ,stat="identity",na.rm = TRUE)+geom_text(aes(label=Throughput), vjust=-1.4, color="black", size=3.4)+labs(title = "Least popular Roots",x="Roots",y="Populations")+theme(plot.title = element_text(hjust = 0.5,face = "bold",color = "black"))+theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
panel.background = element_blank(), axis.line = element_line(colour = "black"))+coord_flip())
Ignoring unknown parameters: bin
#How many people take the BART late at night?
Given Below are the following assumptions for day cycle of the day
12 am - 6 am :- Night. 6 am - 12 noon :- Morning. 12 noon - 6pm :- AfterNoon.2 6pm - 11pm ;- Evening.
ggplotly(ggplot(data[,list(Throughput=sum(Throughput)),by=c("dayCycle")][order(Throughput,dayCycle,decreasing=TRUE)],aes(x=as.factor(dayCycle),y=Throughput))+geom_bar(fill="steelblue",bin = 50,width = 0.2 ,stat="identity",na.rm = TRUE)+geom_text(aes(label=Throughput), vjust=-1.4, color="black", size=3.4)+labs(title = "Number of passengers travelling at particular point of day",x="DayCycle",y="Populations")+theme(plot.title = element_text(hjust = 0.5,face = "bold",color = "black"))+theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
panel.background = element_blank(), axis.line = element_line(colour = "black"))+coord_flip())
Ignoring unknown parameters: bin
data[,list(Throughput=sum(Throughput)),by=c("dayCycle")][order(Throughput,dayCycle,decreasing=TRUE)] %>%
group_by(dayCycle) %>%
plot_ly(labels = ~as.factor(dayCycle), values = ~Throughput) %>%
add_pie(hole = 0.6) %>%
layout(title = "Percentage of passengers on different day cycle of the day", showlegend = F,
xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))
calander chart.
#getSymbols("CMG", src="yahoo")
#data2$year<-as.numeric(data2$date)$year+1900)
# the month too
#data2$month<-as.numeric(as.POSIXlt(data2$date)$mon+1)
# but turn months into ordered facors to control the appearance/ordering in the presentation
#dat$monthf<-factor(dat$month,levels=as.character(1:12),labels=c("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"),ordered=TRUE)
# the day of week is again easily found
#dat$weekday = as.POSIXlt(dat$date)$wday
# again turn into factors to control appearance/abbreviation and ordering
# I use the reverse function rev here to order the week top down in the graph
# you can cut it out to reverse week order
#dat$weekdayf<-factor(dat$weekday,levels=rev(1:7),labels=rev(c("Mon","Tue","Wed","Thu","Fri","Sat","Sun")),ordered=TRUE)
# the monthweek part is a bit trickier
# first a factor which cuts the data into month chunks
#dat$yearmonth<-as.yearmon(dat$date)
#dat$yearmonthf<-factor(dat$yearmonth)
# then find the "week of year" for each day
#dat$week <- as.numeric(format(dat$date,"%W"))
# and now for each monthblock we normalize the week to start at 1
#dat<-ddply(dat,.(yearmonthf),transform,monthweek=1+week-min(week))
#CHECK DATASET
#head(dat)
data$monthf<-factor(data$month,levels=as.character(1:12),labels=c("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"),ordered=TRUE)
unique(data$week)
[1] "Friday" "Saturday" "Sunday" "Monday" "Tuesday" "Wednesday" "Thursday"
data$yearmonth <- as.yearmon(data$DateTime)
data$yearmonthf <- factor(data$yearmonth)
data$week <- as.numeric(format(data$DateTime,"%W"))
data
data<-ddply(data,.(yearmonthf),transform,monthweek=1+week-min(week))
LS0tCnRpdGxlOiAiRURBIGZvciBTYW4gRnJhbmNpc2NvIFRyYW5zcG9ydCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKI0NvbnRleHQKCkJBUlQsIHNob3J0IGZvciAiQmF5IEFyZWEgUmFwaWQgVHJhbnNpdCIsIGlzIHRoZSB0cmFuc2l0IHN5c3RlbSBzZXZlcmluZyB0aGUgU2FuIEZyYW5jaXNjbyBCYXkgQXJlYSBpbiBDYWxpZm9ybmlhLiBCQVJUIG9wZXJhdGVzIHNpeCByb3V0ZXMsIDQ2IHN0YXRpb25zLCBhbmQgYW5kIDExMiBtaWxlcyBvZiB0cmFjay4gSXQgc2VydmVzIGFuIGF2ZXJhZ2Ugd2Vla2RheSByaWRlcnNoaXAgb2YgNDIzLDAwMCBwZW9wbGUsIG1ha2luZyBpdCB0aGUgZmlmdGgtYnVzaWVzdCByYXBpZCB0cmFuc2l0IHN5c3RlbSBpbiB0aGUgVW5pdGVkIFN0YXRlcy4KClRoaXMgZGF0YXNldCBjb250YWlucyBkYWlseSBpbmZvcm1hdGlvbiBvbiBCQVJUIHJpZGVyc2hpcCBmb3IgYSBwZXJpb2QgY292ZXJpbmcgYWxsIG9mIDIwMTYgYW5kIHBhcnQgb2YgMjAxNy4gVW5saWtlIHNvbWUgb3RoZXIgcmFwaWQgdHJhbnNpdCBzeXN0ZW0gZGF0YXNldHMsIHRoaXMgZGF0YSBpbmNsdWRlcyBtb3ZlbWVudHMgYmV0d2VlbiBzcGVjaWZpYyBzdGF0aW9ucyAodGhlcmUgYXJlIGp1c3Qgb3ZlciAyMDAwIHN0YXRpb24tdG8tc3RhdGlvbiBjb21iaW5hdGlvbnMpLgoKI0NvbnRlbnQKClRoaXMgZGF0YXNldCBpcyBzcGxpdCBpbiB0aHJlZSBmaWxlcy4gc3RhdGlvbl9pbmZvLmNzdiBpbmNsdWRlcyBnZW5lcmljIGluZm9ybWF0aW9uIG9uIGluZGl2aWR1YWwgc3RhdGlvbnMuIGRhdGUtaG91ci1zb28tZGVzdC0yMDE3LmNzdiBjb250YWlucyBkYWlseSBpbnRlci1zdGF0aW9uIHJpZGVyc2hpcCBmb3IgKHBhcnQgb2YpIDIwMTcuIGRhdGUtaG91ci1zb28tZGVzdC0yMDE2LmNzdiBjb250YWlucyBkYWlseSBpbnRlci1zdGF0aW9uIHJpZGVyc2hpcCBmb3IgYWxsIG9mIDIwMTYuCgojUXVlc3Rpb25zIHRoYXQgYXJlIHRvIGJlIGFuc3dlcmVkCgpXaGljaCBCQVJUIHN0YXRpb24gaXMgdGhlIGJ1c2llc3Q/ClRvcCA1IHBvcHVsYXIgcm91dGVzPwpXaGF0IGlzIHRoZSBsZWFzdCBwb3B1bGFyIEJBUlQgcm91dGU/CldoZW4gaXMgdGhlIGJlc3QgdGltZSB0byBnbyB0byBTRiBpZiB5b3Ugd2FudCB0byBmaW5kIGEgc2VhdD8KV2hpY2ggZGF5IG9mIHRoZSB3ZWVrIGlzIHRoZSBidXNpZXN0PwpIb3cgbWFueSBwZW9wbGUgdGFrZSB0aGUgQkFSVCBsYXRlIGF0IG5pZ2h0PwpEb2VzIHRoZSBCQVJUIGV2ZXIgc3RvcCBpbiBhIHN0YXRpb24gd2l0aG91dCBhbnlvbmUgZ29pbmcgb2ZmIG9yIG9uPwoKTm90ZSA6LSBOdW1iZXIgb2YgcGFzc2VuZ2VycyAoVGhyb3VnaHB1dCkgdGhhdCB3ZW50IGJldHdlZW4gdHdvIHN0YXRpb25zIChPcmlnaW4gYW5kIERlc3RpbmF0aW9uKSBpbiBhIGdpdmVuIHRpbWUgKERhdGVUaW1lKSBpbiAyMDE3LgoKbGlicmFyaWVzIHVzZWQgZm9yIHRoZSBFREEuCmBgYHtyfQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwbG90bHkpCmxpYnJhcnkoem9vKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShxdWFudG1vZCkKbGlicmFyeShyZXNoYXBlMikKbGlicmFyeShwbHlyKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShSQ29sb3JCcmV3ZXIpCiNsaWJyYXJ5KGRldnRvb2xzKQpgYGAKClJlYWRpbmcgYWxsIHRoZSBkYXRhIGludG8gIFIuCmBgYHtyfQpkYXRhMSA8LSBmcmVhZCgiZGF0ZS1ob3VyLXNvby1kZXN0LTIwMTYuY3N2IixzdHJpbmdzQXNGYWN0b3JzID0gVFJVRSkKZGF0YTIgPC0gZnJlYWQoImRhdGUtaG91ci1zb28tZGVzdC0yMDE3LmNzdiIsc3RyaW5nc0FzRmFjdG9ycyA9IFRSVUUpCmRhdGEzIDwtIGZyZWFkKCJzdGF0aW9uX2luZm8uY3N2IixzdHJpbmdzQXNGYWN0b3JzID0gVFJVRSkKYGBgCkFzIHRoZSBkYXRhMSBhbmQgZGF0YTIgcmVwcmVzZW50IHRoZSBzYW1lIHN0cnVjdHVyZSBvZiB0aGUgZGF0YSxzbyBub3cgd2UgYXJlIG1lcmdpbmcgdGhvc2UgMiBkYXRhCmBgYHtyfQpkYXRhPC1yYmluZChkYXRhMSxkYXRhMikKYGBgCgpSZW1vdmluZyB0aGUgYWJvdmUgMiBkYXRhIGZyYW1lcyBpbiBSCmBgYHtyfQpybShkYXRhMSkKcm0oZGF0YTIpCmBgYAoKY29udmVydGluZyB0aGUgZGF0ZSB0aW1lIGNvbHVtbiBjb3JyZWN0IGZvcm1hdCBpbiBSLgpgYGB7cn0KZGF0YSREYXRlVGltZSAgPC0gYXMuUE9TSVhjdChkYXRhJERhdGVUaW1lLCBmb3JtYXQ9IiVZLSVtLSVkICVIOiVNOiVTIikKYGBgCgoKCgpOb3cgd2UgYXJlIGV4dHJhY3RpbmcgbW9udGhzLHllYXIsd2Vla2RheXMsaG91cnMKYGBge3J9CmRhdGEkeWVhcj15ZWFyKGRhdGEkRGF0ZVRpbWUpCmRhdGEkbW9udGg9bW9udGgoZGF0YSREYXRlVGltZSkKZGF0YSR3ZWVrRGF5cz13ZWVrZGF5cyhkYXRhJERhdGVUaW1lKQpkYXRhJGhvdXJzID0gaG91cihkYXRhJERhdGVUaW1lKQpgYGAKCk5vdyB3ZSBhcmUgZXh0cmFjdGluZyBzZWFzb25zLgoKU3ByaW5nIDotIE1hcmNoLEFwcmlsLE1heQpTdW1tZXIgOi0gSnVuZSxKdWx5LEF1Z3VzdApBdXR1bSA6LSBTZXB0ZW1iZXIsT2N0b2JlcixOb3ZlbWJlcgpXaW50ZXIgOi0gRGVjZW1iZXIsSmFudWFyeSxGZWJydWFyeQpgYGB7cn0KaW5keCA8LSBzZXROYW1lcyggcmVwKGMoJ3dpbnRlcicsICdzcHJpbmcnLCAnc3VtbWVyJywKICAgICAgICAgICAgICAgICAgICdmYWxsJyksZWFjaD0zKSwgYygxMiwxOjExKSkKI2RhdGExPWRhdGEKZGF0YSRzZWFzb248LXVubmFtZShpbmR4W2FzLmNoYXJhY3RlcihkYXRhJG1vbnRoKV0pCmBgYAoKRXh0cmFjdGluZyBob3VycyBmcm9tIGRhdGUgdGltZSBjb2x1bW4uClRoaXMgaXMgMjQgaG91cnMgY2xvY2sKCjEyIGFtIC0gNiBhbSA6LSBOaWdodC4KNiBhbSAtIDEyIG5vb24gOi0gTW9ybmluZy4KMTIgbm9vbiAtIDZwbSA6LSBBZnRlck5vb24uMgo2cG0gLSAxMXBtIDstIEV2ZW5pbmcuCmBgYHtyfQojIGNyZWF0ZSBicmVha3MKYnJlYWtzIDwtIGhvdXIoaG1zKCIwMDowMCIsICI2OjAwIiwgIjEyOjAwIiwgIjE4OjAwIiwgIjIzOjU5IikpCiMgbGFiZWxzIGZvciB0aGUgYnJlYWtzCmxhYmVscyA8LSBjKCJOaWdodCIsICJNb3JuaW5nIiwgIkFmdGVybm9vbiIsICJFdmVuaW5nIikKCmRhdGEkZGF5Q3ljbGUgPC0gY3V0KHg9aG91cihkYXRhJERhdGVUaW1lKSwgYnJlYWtzID0gYnJlYWtzLCBsYWJlbHMgPSBsYWJlbHMsIGluY2x1ZGUubG93ZXN0PVRSVUUpCiN1bmlxdWUoaG91cihkYXRhJERhdGVUaW1lKSkKdW5pcXVlKGRhdGEkZGF5Q3ljbGUpCmBgYAoKCmNoZWNraW5nIGhvdyBtYW55IHVuaXF1ZSBzb3VyY2Ugc3RhdGlvbnMKYGBge3J9CmNhdCgiVGhlIG51bWJlciBvZiBvcmlnaW4gc3RhdGlvbnMgaXMgOi0gICIsIGxlbmd0aCh1bmlxdWUoZGF0YSRPcmlnaW4pKSkKY2F0KCJcbiBUaGUgbnVtYmVyIG9mIERlc3RpbmF0aW9uIHN0YXRpb25zIGlzIDotICAiLCBsZW5ndGgodW5pcXVlKGRhdGEkRGVzdGluYXRpb24pKSkKYGBgCnNvIHRoZXJlIGFyZSA0NiB0aGUgbnVtYmVyIG9mIG9yaWdpbiBhbmQgZGVzdGluZGF0aW9uIHBsYWNlcyBhcmUgNDYuCgpjaGVja2luZyB0aG9zZSBlbnRyaWVzIHdobyAncyBzb3VyY2UgYW5kIGRlc3RpbmF0aW9uIGlzIHNhbWUuCmBgYHtyfQpsZW5ndGgoZGF0YVtkYXRhJE9yaWdpbj09ZGF0YSREZXN0aW5hdGlvbixdW09yaWdpbj09IjEyVEgiLC5OLGMoJ09yaWdpbicsJ0Rlc3RpbmF0aW9uJywnaG91cnMnLCdUaHJvdWdocHV0JyldKQpgYGAKCmBgYHtyfQp1bmlxdWUoZGF0YVtkYXRhJE9yaWdpbj09ZGF0YSREZXN0aW5hdGlvbixdWyxjKCJPcmlnaW4iLCJEZXN0aW5hdGlvbiIpXSkKYGBgCgoKVGhlIHNvdXJjZSBhbmQgZGVzdGluYXRpb24gYXJlIHNhbWUgLHRoYXQgJ3MgIGJlY2F1c2UgdGhlIHBlb3BsZSB3ZXJlIHN0YXlpbmcgaW4gdGhlIHNhbWUgc3RhdGlvbiBmb3IgdGhhdCBwYXJ0aWN1bGFyIGhvdXIuc28gdGhpcyBkYXRhIHRlbGxzIGFib3V0IHRoZXNlIHBlb3BsZS4gCgoKI1doaWNoIEJBUlQgc3RhdGlvbiBpcyB0aGUgYnVzaWVzdD8KCmBgYHtyfQpkYXRhMT1kYXRhWyxsaXN0KFRocm91Z2hwdXQ9c3VtKFRocm91Z2hwdXQpKSwgYnk9J0Rlc3RpbmF0aW9uJ11bb3JkZXIoVGhyb3VnaHB1dCxEZXN0aW5hdGlvbixkZWNyZWFzaW5nPVRSVUUpXQpgYGAKCgpQbG90dGluZyB0aGUgdG9wIDUgYnVzaWVzdCBzdGF0aW9ucy4KYGBge3J9CmdncGxvdGx5KCBnZ3Bsb3QoZGF0YTFbMTo1LF0sYWVzKHg9YXMuZmFjdG9yKERlc3RpbmF0aW9uKSx5PVRocm91Z2hwdXQpKSsKICBnZW9tX3NlZ21lbnQoIGFlcyh4PWFzLmZhY3RvcihEZXN0aW5hdGlvbiksIHhlbmQ9YXMuZmFjdG9yKERlc3RpbmF0aW9uKSwgeT0wLCB5ZW5kPVRocm91Z2hwdXQpKSAreWxpbSgwLDIyMDAwMDAwKSsKICBnZW9tX3BvaW50KCBzaXplPTUsIGNvbG9yPSJzdGVlbGJsdWUiLCBmaWxsPWFscGhhKCJzdGVlbGJsdWUiLCAwLjMpLCBhbHBoYT0wLjcsIHNoYXBlPTIxLCBzdHJva2U9MikrdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJyB3aGl0ZScpKStnZW9tX3RleHQoYWVzKGxhYmVsPVRocm91Z2hwdXQpLCB2anVzdD0tMiwgY29sb3I9ImJsYWNrIiwgc2l6ZT0zLjQpK2Nvb3JkX2ZsaXAoKStsYWJzKHRpdGxlID0gIlRoZSBUb3AgNSBidXNpZXN0IEJBUlQgU3RhdGlvbnMiLHg9IlN0YXRpb24gY29kZSIseT0iUG9wdWxhdGlvbiIpK3RoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsZmFjZSA9ICJib2xkIixjb2xvciA9ICJCbGFjayIpKSkKYGBgCkFzIHdlIHNlZSBFbWJhcmNhZGVybyAoRU1CUikgaXMgdGhlIEJBUlQgc3RhdGlvbiB3YXMgdGhlIG1vc3QgYnVzZXN0IHN0YXRpb24gaW4gMjAxNiBhbmQgMjAxNyAsZm9sbG93ZWQgYnkgTW9udGdvbWVyeSBTdC4gKE1PTlQpLApQb3dlbGwgU3QuIChQT1dMKSxDaXZpYyBDZW50ZXIvVU4gUGxhemEgKENJVkMpIGFuZCBEb3dudG93biBCZXJrZWxleSAoREJSSykKCkxlYXN0IHBvcHVsYXIgQkFSVCBzdGF0aW9uLgpgYGB7cn0KZ2dwbG90bHkoZ2dwbG90KGRhdGExWzQxOjQ1LF0sYWVzKHg9YXMuZmFjdG9yKERlc3RpbmF0aW9uKSx5PVRocm91Z2hwdXQpKSsKICBnZW9tX3NlZ21lbnQoIGFlcyh4PWFzLmZhY3RvcihEZXN0aW5hdGlvbiksIHhlbmQ9YXMuZmFjdG9yKERlc3RpbmF0aW9uKSwgeT0wLCB5ZW5kPVRocm91Z2hwdXQpKSAreWxpbSgwLDIyMDAwMDApKwogIGdlb21fcG9pbnQoIHNpemU9NSwgY29sb3I9InN0ZWVsYmx1ZSIsIGZpbGw9YWxwaGEoInN0ZWVsYmx1ZSIsIDAuMyksIGFscGhhPTAuNywgc2hhcGU9MjEsIHN0cm9rZT0yKSt0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAnIHdoaXRlJykpK2dlb21fdGV4dChhZXMobGFiZWw9VGhyb3VnaHB1dCksIHZqdXN0PS0xLCBjb2xvcj0iYmxhY2siLCBzaXplPTMuNCkrY29vcmRfZmxpcCgpK2xhYnModGl0bGUgPSAiVGhlIExlYXN0IDUgYnVzaWVzdCBCQVJUIFN0YXRpb25zIix4PSJTdGF0aW9uIGNvZGUiLHk9IlBvcHVsYXRpb24iKSt0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LGZhY2UgPSAiYm9sZCIsY29sb3IgPSAiQmxhY2siKSkpCmBgYApUaGUgbGVhc3QgYnVzaWVzdCBzdGF0aW9ucyBhcmUgT2FrbGFuZCBBaXJwb3J0IChPQUtMKS4KCgoKU2hvd2luZyB0aGVzZSBzdGF0cyBvZiBwb3B1bGF0aW9uIGluIHRlcm1zIG9mIHBlcmNlbnRhZ2UuCmBgYHtyfQpkYXRhMSAlPiUKICBncm91cF9ieShEZXN0aW5hdGlvbikgICU+JQogIHBsb3RfbHkobGFiZWxzID0gfmFzLmZhY3RvcihEZXN0aW5hdGlvbiksIHZhbHVlcyA9IH5UaHJvdWdocHV0KSAlPiUKICBhZGRfcGllKGhvbGUgPSAwLjYpICU+JQogIGxheW91dCh0aXRsZSA9ICJUaGUgUG9wdWxhdGlvbiBpbiBCQVJUIFN0YXRpb25zIiwgIHNob3dsZWdlbmQgPSBGLAogICAgICAgICB4YXhpcyA9IGxpc3Qoc2hvd2dyaWQgPSBGQUxTRSwgemVyb2xpbmUgPSBGQUxTRSwgc2hvd3RpY2tsYWJlbHMgPSBGQUxTRSksCiAgICAgICAgIHlheGlzID0gbGlzdChzaG93Z3JpZCA9IEZBTFNFLCB6ZXJvbGluZSA9IEZBTFNFLCBzaG93dGlja2xhYmVscyA9IEZBTFNFKSkKCmBgYApyZW1vdmluZyB0aGUgc3Vic2V0IGRhdGEuCmBgYHtyfQpybShkYXRhMSkKYGBgCgojV2hhdCBpcyB0aGUgbGVhc3QgcG9wdWxhciBCQVJUIHJvdXRlPwoKYGBge3J9CmRhdGEkcm9vdHM8LSB3aXRoKGRhdGEsIHBhc3RlMChPcmlnaW4sIi0iLERlc3RpbmF0aW9uKSkKZGF0YQpgYGAKCgpgYGB7cn0KZGF0YVshKE9yaWdpbj09RGVzdGluYXRpb24pLGxpc3QoVGhyb3VnaHB1dD1zdW0oVGhyb3VnaHB1dCkpLGJ5PWMoInJvb3RzIildW29yZGVyKFRocm91Z2hwdXQscm9vdHMsZGVjcmVhc2luZz1UUlVFKV0KYGBgCgpgYGB7cn0KZ2dwbG90bHkoIGdncGxvdChkYXRhWyEoT3JpZ2luPT1EZXN0aW5hdGlvbiksbGlzdChUaHJvdWdocHV0PXN1bShUaHJvdWdocHV0KSksYnk9Yygicm9vdHMiKV1bb3JkZXIoVGhyb3VnaHB1dCxyb290cyxkZWNyZWFzaW5nPVRSVUUpXVsxOjUsXSxhZXMoeD1hcy5mYWN0b3Iocm9vdHMpLHk9VGhyb3VnaHB1dCkpK2dlb21fYmFyKGZpbGw9InN0ZWVsYmx1ZSIsYmluID0gNTAsd2lkdGggPSAwLjIgLHN0YXQ9ImlkZW50aXR5IixuYS5ybSA9IFRSVUUpK2dlb21fdGV4dChhZXMobGFiZWw9VGhyb3VnaHB1dCksIHZqdXN0PS0xLCBjb2xvcj0iYmxhY2siLCBzaXplPTMuNCkrbGFicyh0aXRsZSA9ICJUaGUgdG9wIDUgYnVzeSByb290cyBvZiBCQVJUIix4PSJSb290cyIseT0iUG9wdWxhdGlvbnMiKSt0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LGZhY2UgPSAiYm9sZCIsY29sb3IgPSAiYmxhY2siKSkrdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIpKStjb29yZF9mbGlwKCkpCmBgYApgYGB7cn0KZ2dwbG90bHkoZ2dwbG90KGRhdGFbIShPcmlnaW49PURlc3RpbmF0aW9uKSxsaXN0KFRocm91Z2hwdXQ9c3VtKFRocm91Z2hwdXQpKSxieT1jKCJyb290cyIpXVtvcmRlcihUaHJvdWdocHV0LHJvb3RzLGRlY3JlYXNpbmc9VFJVRSldWzIwNjU6MjA3MCxdLGFlcyh4PWFzLmZhY3Rvcihyb290cykseT1UaHJvdWdocHV0KSkrZ2VvbV9iYXIoZmlsbD0ic3RlZWxibHVlIixiaW4gPSA1MCx3aWR0aCA9IDAuMiAsc3RhdD0iaWRlbnRpdHkiLG5hLnJtID0gVFJVRSkrZ2VvbV90ZXh0KGFlcyhsYWJlbD1UaHJvdWdocHV0KSwgdmp1c3Q9LTEuNCwgY29sb3I9ImJsYWNrIiwgc2l6ZT0zLjQpK2xhYnModGl0bGUgPSAiTGVhc3QgcG9wdWxhciBSb290cyIseD0iUm9vdHMiLHk9IlBvcHVsYXRpb25zIikrdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSxmYWNlID0gImJvbGQiLGNvbG9yID0gImJsYWNrIikpK3RoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCnBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSkrY29vcmRfZmxpcCgpKQpgYGAKCiNIb3cgbWFueSBwZW9wbGUgdGFrZSB0aGUgQkFSVCBsYXRlIGF0IG5pZ2h0PwoKR2l2ZW4gIEJlbG93IGFyZSB0aGUgZm9sbG93aW5nIGFzc3VtcHRpb25zIGZvciBkYXkgY3ljbGUgb2YgdGhlIGRheSAKCjEyIGFtIC0gNiBhbSA6LSBOaWdodC4KNiBhbSAtIDEyIG5vb24gOi0gTW9ybmluZy4KMTIgbm9vbiAtIDZwbSA6LSBBZnRlck5vb24uMgo2cG0gLSAxMXBtIDstIEV2ZW5pbmcuCgoKYGBge3J9CmdncGxvdGx5KGdncGxvdChkYXRhWyxsaXN0KFRocm91Z2hwdXQ9c3VtKFRocm91Z2hwdXQpKSxieT1jKCJkYXlDeWNsZSIpXVtvcmRlcihUaHJvdWdocHV0LGRheUN5Y2xlLGRlY3JlYXNpbmc9VFJVRSldLGFlcyh4PWFzLmZhY3RvcihkYXlDeWNsZSkseT1UaHJvdWdocHV0KSkrZ2VvbV9iYXIoZmlsbD0ic3RlZWxibHVlIixiaW4gPSA1MCx3aWR0aCA9IDAuMiAsc3RhdD0iaWRlbnRpdHkiLG5hLnJtID0gVFJVRSkrZ2VvbV90ZXh0KGFlcyhsYWJlbD1UaHJvdWdocHV0KSwgdmp1c3Q9LTEuNCwgY29sb3I9ImJsYWNrIiwgc2l6ZT0zLjQpK2xhYnModGl0bGUgPSAiTnVtYmVyIG9mIHBhc3NlbmdlcnMgdHJhdmVsbGluZyBhdCBwYXJ0aWN1bGFyIHBvaW50IG9mIGRheSIseD0iRGF5Q3ljbGUiLHk9IlBvcHVsYXRpb25zIikrdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSxmYWNlID0gImJvbGQiLGNvbG9yID0gImJsYWNrIikpK3RoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCnBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSkrY29vcmRfZmxpcCgpKQpgYGAKCgoKYGBge3J9CmRhdGFbLGxpc3QoVGhyb3VnaHB1dD1zdW0oVGhyb3VnaHB1dCkpLGJ5PWMoImRheUN5Y2xlIildW29yZGVyKFRocm91Z2hwdXQsZGF5Q3ljbGUsZGVjcmVhc2luZz1UUlVFKV0gICU+JQogIGdyb3VwX2J5KGRheUN5Y2xlKSAgJT4lCiAgcGxvdF9seShsYWJlbHMgPSB+YXMuZmFjdG9yKGRheUN5Y2xlKSwgdmFsdWVzID0gflRocm91Z2hwdXQpICU+JQogIGFkZF9waWUoaG9sZSA9IDAuNikgJT4lCiAgbGF5b3V0KHRpdGxlID0gIlBlcmNlbnRhZ2Ugb2YgcGFzc2VuZ2VycyBvbiBkaWZmZXJlbnQgZGF5IGN5Y2xlIG9mIHRoZSBkYXkiLCAgc2hvd2xlZ2VuZCA9IEYsCiAgICAgICAgIHhheGlzID0gbGlzdChzaG93Z3JpZCA9IEZBTFNFLCB6ZXJvbGluZSA9IEZBTFNFLCBzaG93dGlja2xhYmVscyA9IEZBTFNFKSwKICAgICAgICAgeWF4aXMgPSBsaXN0KHNob3dncmlkID0gRkFMU0UsIHplcm9saW5lID0gRkFMU0UsIHNob3d0aWNrbGFiZWxzID0gRkFMU0UpKQpgYGAKY2FsYW5kZXIgY2hhcnQuCmBgYHtyfQojZ2V0U3ltYm9scygiQ01HIiwgc3JjPSJ5YWhvbyIpCmBgYAoKYGBge3J9CiNkYXRhMiR5ZWFyPC1hcy5udW1lcmljKGRhdGEyJGRhdGUpJHllYXIrMTkwMCkKIyB0aGUgbW9udGggdG9vIAojZGF0YTIkbW9udGg8LWFzLm51bWVyaWMoYXMuUE9TSVhsdChkYXRhMiRkYXRlKSRtb24rMSkKIyBidXQgdHVybiBtb250aHMgaW50byBvcmRlcmVkIGZhY29ycyB0byBjb250cm9sIHRoZSBhcHBlYXJhbmNlL29yZGVyaW5nIGluIHRoZSBwcmVzZW50YXRpb24KI2RhdCRtb250aGY8LWZhY3RvcihkYXQkbW9udGgsbGV2ZWxzPWFzLmNoYXJhY3RlcigxOjEyKSxsYWJlbHM9YygiSmFuIiwiRmViIiwiTWFyIiwiQXByIiwiTWF5IiwiSnVuIiwiSnVsIiwiQXVnIiwiU2VwIiwiT2N0IiwiTm92IiwiRGVjIiksb3JkZXJlZD1UUlVFKQojIHRoZSBkYXkgb2Ygd2VlayBpcyBhZ2FpbiBlYXNpbHkgZm91bmQKI2RhdCR3ZWVrZGF5ID0gYXMuUE9TSVhsdChkYXQkZGF0ZSkkd2RheQojIGFnYWluIHR1cm4gaW50byBmYWN0b3JzIHRvIGNvbnRyb2wgYXBwZWFyYW5jZS9hYmJyZXZpYXRpb24gYW5kIG9yZGVyaW5nCiMgSSB1c2UgdGhlIHJldmVyc2UgZnVuY3Rpb24gcmV2IGhlcmUgdG8gb3JkZXIgdGhlIHdlZWsgdG9wIGRvd24gaW4gdGhlIGdyYXBoCiMgeW91IGNhbiBjdXQgaXQgb3V0IHRvIHJldmVyc2Ugd2VlayBvcmRlcgojZGF0JHdlZWtkYXlmPC1mYWN0b3IoZGF0JHdlZWtkYXksbGV2ZWxzPXJldigxOjcpLGxhYmVscz1yZXYoYygiTW9uIiwiVHVlIiwiV2VkIiwiVGh1IiwiRnJpIiwiU2F0IiwiU3VuIikpLG9yZGVyZWQ9VFJVRSkKIyB0aGUgbW9udGh3ZWVrIHBhcnQgaXMgYSBiaXQgdHJpY2tpZXIgCiMgZmlyc3QgYSBmYWN0b3Igd2hpY2ggY3V0cyB0aGUgZGF0YSBpbnRvIG1vbnRoIGNodW5rcwojZGF0JHllYXJtb250aDwtYXMueWVhcm1vbihkYXQkZGF0ZSkKI2RhdCR5ZWFybW9udGhmPC1mYWN0b3IoZGF0JHllYXJtb250aCkKIyB0aGVuIGZpbmQgdGhlICJ3ZWVrIG9mIHllYXIiIGZvciBlYWNoIGRheQojZGF0JHdlZWsgPC0gYXMubnVtZXJpYyhmb3JtYXQoZGF0JGRhdGUsIiVXIikpCiMgYW5kIG5vdyBmb3IgZWFjaCBtb250aGJsb2NrIHdlIG5vcm1hbGl6ZSB0aGUgd2VlayB0byBzdGFydCBhdCAxIAojZGF0PC1kZHBseShkYXQsLih5ZWFybW9udGhmKSx0cmFuc2Zvcm0sbW9udGh3ZWVrPTErd2Vlay1taW4od2VlaykpCgojQ0hFQ0sgREFUQVNFVAojaGVhZChkYXQpCmBgYAoKYGBge3J9CmRhdGEkbW9udGhmPC1mYWN0b3IoZGF0YSRtb250aCxsZXZlbHM9YXMuY2hhcmFjdGVyKDE6MTIpLGxhYmVscz1jKCJKYW4iLCJGZWIiLCJNYXIiLCJBcHIiLCJNYXkiLCJKdW4iLCJKdWwiLCJBdWciLCJTZXAiLCJPY3QiLCJOb3YiLCJEZWMiKSxvcmRlcmVkPVRSVUUpCmBgYAoKYGBge3J9CnVuaXF1ZShkYXRhJHdlZWspCmBgYAoKCmBgYHtyfQpkYXRhJHllYXJtb250aCA8LSBhcy55ZWFybW9uKGRhdGEkRGF0ZVRpbWUpCmRhdGEkeWVhcm1vbnRoZiA8LSBmYWN0b3IoZGF0YSR5ZWFybW9udGgpCmBgYAoKCmBgYHtyfQpkYXRhJHdlZWsgPC0gYXMubnVtZXJpYyhmb3JtYXQoZGF0YSREYXRlVGltZSwiJVciKSkKYGBgCgpgYGB7cn0KZGF0YQpgYGAKCmBgYHtyfQpkYXRhPC1kZHBseShkYXRhLC4oeWVhcm1vbnRoZiksdHJhbnNmb3JtLG1vbnRod2Vlaz0xK3dlZWstbWluKHdlZWspKQpgYGAKCgo=